`timescale 1ns / 1ps


module axi_slave#(
    parameter integer C_S_AXI_ID_WIDTH = 1,
    parameter integer C_S_AXI_DATA_WIDTH	= 32,
	  parameter integer C_S_AXI_ADDR_WIDTH	= 32,
	  parameter integer C_S_AXI_AWUSER_WIDTH	= 0,
	  parameter integer C_S_AXI_ARUSER_WIDTH	= 0,
	  parameter integer C_S_AXI_WUSER_WIDTH	= 0,
	  parameter integer C_S_AXI_RUSER_WIDTH	= 0,
	  parameter integer C_S_AXI_BUSER_WIDTH	= 0
  )(
		input logic                                 S_AXI_ACLK,
		input logic                                 S_AXI_ARESETN,
		input logic [C_S_AXI_ID_WIDTH-1 : 0]        S_AXI_AWID,
		input logic [C_S_AXI_ADDR_WIDTH-1 : 0]      S_AXI_AWADDR,
		input logic [7 : 0]                         S_AXI_AWLEN,
		input logic [2 : 0]                         S_AXI_AWSIZE,
		input logic [1 : 0]                         S_AXI_AWBURST,
		input logic                                 S_AXI_AWLOCK,
		input logic [3 : 0]                         S_AXI_AWCACHE,
		input logic [2 : 0]                         S_AXI_AWPROT,
		input logic [3 : 0]                         S_AXI_AWQOS,
		input logic [3 : 0]                         S_AXI_AWREGION,
		input logic [C_S_AXI_AWUSER_WIDTH-1 : 0]    S_AXI_AWUSER,
		input logic                                 S_AXI_AWVALID,
		output logic                                S_AXI_AWREADY,

		input logic [C_S_AXI_DATA_WIDTH-1 : 0]      S_AXI_WDATA,
		input logic [(C_S_AXI_DATA_WIDTH/8)-1 : 0]  S_AXI_WSTRB,
		input logic                                 S_AXI_WLAST,
		input logic [C_S_AXI_WUSER_WIDTH-1 : 0]     S_AXI_WUSER,
		input logic                                 S_AXI_WVALID,
		output logic                                S_AXI_WREADY,

		output logic [C_S_AXI_ID_WIDTH-1 : 0]       S_AXI_BID,
		output logic [1 : 0]                        S_AXI_BRESP,
		output logic [C_S_AXI_BUSER_WIDTH-1 : 0]    S_AXI_BUSER,
		output logic                                S_AXI_BVALID,
		input logic                                 S_AXI_BREADY,

		input logic [C_S_AXI_ID_WIDTH-1 : 0]        S_AXI_ARID,
		input logic [C_S_AXI_ADDR_WIDTH-1 : 0]      S_AXI_ARADDR,
		input logic [7 : 0]                         S_AXI_ARLEN,
		input logic [2 : 0]                         S_AXI_ARSIZE,
		input logic [1 : 0]                         S_AXI_ARBURST,
		input logic                                 S_AXI_ARLOCK,
		input logic [3 : 0]                         S_AXI_ARCACHE,
		input logic [2 : 0]                         S_AXI_ARPROT,
		input logic [3 : 0]                         S_AXI_ARQOS,
		input logic [3 : 0]                         S_AXI_ARREGION,
		input logic [C_S_AXI_ARUSER_WIDTH-1 : 0]    S_AXI_ARUSER,
		input logic                                 S_AXI_ARVALID,
		output logic                                S_AXI_ARREADY,

		output logic [C_S_AXI_ID_WIDTH-1 : 0]       S_AXI_RID,
		output logic [C_S_AXI_DATA_WIDTH-1 : 0]     S_AXI_RDATA,
		output logic [1 : 0]                        S_AXI_RRESP,
		output logic                                S_AXI_RLAST,
		output logic [C_S_AXI_RUSER_WIDTH-1 : 0]    S_AXI_RUSER,
		output logic                                S_AXI_RVALID,
		input logic                                 S_AXI_RREADY,
		//Bram for A  B C martix
		output logic 																bram_clk,
		output logic		 														bram_rstn,
		output logic                                bram_en,
		output logic [7:0]                         	bram_addr,       
    output logic [C_S_AXI_DATA_WIDTH-1 : 0]    	bram_wrdata,      
    input  logic [C_S_AXI_DATA_WIDTH-1 : 0]     bram_rddata,      
    output logic [3:0]                          bram_we
  );
  logic w_aw_active;
	logic w_w_active ;
	logic w_b_active ;
	logic w_ar_active;
	logic w_r_active ;
	//有效信号赋值
	assign w_aw_active =  S_AXI_AWVALID & S_AXI_AWREADY  ;
	assign w_w_active  =  S_AXI_WVALID& S_AXI_WREADY     ;
	assign w_b_active  =  S_AXI_BVALID& S_AXI_BREADY     ;
	assign w_ar_active =  S_AXI_ARVALID& S_AXI_ARREADY   ;
	assign w_r_active  =  S_AXI_RVALID& S_AXI_RREADY     ;
	// AXI4FULL signals
	logic [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_awaddr;//Important(Bram)
	logic  	axi_awready;
	logic  	axi_wready;
	logic [1 : 0] 	axi_bresp;
	logic [C_S_AXI_BUSER_WIDTH-1 : 0] 	axi_buser;
	logic  	axi_bvalid;
	logic [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_araddr;//Important
	logic  	axi_arready;
	logic [C_S_AXI_DATA_WIDTH-1 : 0] 	axi_rdata;
	logic [1 : 0] 	axi_rresp;
	logic  	axi_rlast;
	logic [C_S_AXI_RUSER_WIDTH-1 : 0] 	axi_ruser;
	logic  	axi_rvalid;
	
	logic aw_wrap_en;
	logic ar_wrap_en;
	logic [31:0]  aw_wrap_size ;//数据量大小（单位是字节byte）
	logic [31:0]  ar_wrap_size ; 
	logic axi_awv_awr_flag;//有效标志
	logic axi_arv_arr_flag; 
	logic [7:0] axi_awlen_cntr;//计数器节拍
	logic [7:0] axi_arlen_cntr;
	logic [1:0] axi_arburst;
	logic [1:0] axi_awburst;
	logic [7:0] axi_arlen;
	logic [7:0] axi_awlen;
	//local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
	//ADDR_LSB is used for addressing 32/64 bit registers/memories
	//ADDR_LSB = 2 for 32 bits (n downto 2) 
	//ADDR_LSB = 3 for 64 bits (n downto 3)
	localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32)+ 1;//低地址（取9:2）有效的位
	localparam integer OPT_MEM_ADDR_BITS = 7;//给外部Memory的地址（必须要加的）
	//----------------------------------------------
	//-- Signals for user logic memory space example
	//------------------------------------------------
	genvar i;
	genvar j;
	genvar mem_byte_index;
	// I/O Connections assignments
	assign S_AXI_AWREADY	= axi_awready;
	assign S_AXI_WREADY	= axi_wready;
	assign S_AXI_BRESP	= axi_bresp;
	assign S_AXI_BUSER	= axi_buser;
	assign S_AXI_BVALID	= axi_bvalid;
	assign S_AXI_ARREADY	= axi_arready;
	assign S_AXI_RDATA	= bram_rddata;
	assign S_AXI_RRESP	= axi_rresp;
	assign S_AXI_RLAST	= axi_rlast;
	assign S_AXI_RUSER	= axi_ruser;
	assign S_AXI_RVALID	= axi_rvalid;
	assign S_AXI_BID = S_AXI_AWID;
	assign S_AXI_RID = S_AXI_ARID;
	assign  aw_wrap_size = (C_S_AXI_DATA_WIDTH/8 * (axi_awlen)); //len在这里用到了
	assign  ar_wrap_size = (C_S_AXI_DATA_WIDTH/8 * (axi_arlen)); 
	assign  aw_wrap_en = ((axi_awaddr & aw_wrap_size) == aw_wrap_size)? 1'b1: 1'b0;
	assign  ar_wrap_en = ((axi_araddr & ar_wrap_size) == ar_wrap_size)? 1'b1: 1'b0;

	// Implement axi_awready generation

	always_ff @( posedge S_AXI_ACLK )
    begin
	    if ( S_AXI_ARESETN == 1'b0 )
        begin
	        axi_awready <= 1'b0;
	        axi_awv_awr_flag <= 1'b0;
	    end 
	    else 
        begin    
	        if (~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)
          	begin
	        	  axi_awready <= 1'b1;//读写都都没有效的情况
	        	  axi_awv_awr_flag  <= 1'b1;//aw有效
	        	end
	        else if (S_AXI_WLAST && axi_wready)
          	begin
	        	  axi_awv_awr_flag  <= 1'b0;
	        	end
	        else 
          	begin
	        	  axi_awready <= 1'b0;
	        	end
	    end 
	end       
	// Implement axi_awaddr latching 

	always_ff @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_awaddr <= 0;
	      axi_awlen_cntr <= 0;
	      axi_awburst <= 0;
	      axi_awlen <= 0;
	    end 
	  else
	    begin    
	      if (~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag)
	      	begin
	          axi_awaddr <= S_AXI_AWADDR[C_S_AXI_ADDR_WIDTH - 1:0];  
	          axi_awburst <= S_AXI_AWBURST;//记录突发传输
	          axi_awlen <= S_AXI_AWLEN;
	          axi_awlen_cntr <= 0;
	        end   
	      else if((axi_awlen_cntr <= axi_awlen) && axi_wready && S_AXI_WVALID)        
	        begin
						//握手成功，且计数器小于总长度（支持突发传输）
	          axi_awlen_cntr <= axi_awlen_cntr + 1;

	          case (axi_awburst)
	            2'b00: // 固定突发（固定一个地址进行突发传输）
	              begin
	                axi_awaddr <= axi_awaddr;          
	                //for awsize = 4 bytes (010)
	              end   
	            2'b01: //增量突发（递增形式的地址）
	            // The write address for all the beats in the transaction are increments by awsize
	              begin
	                axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                //awaddr aligned to 4 byte boundary 只保存，增量为1，但是32bit对应的地址就相当于是增加了0x04
	                axi_awaddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};
	                //for awsize = 4 bytes (010) 4个字节（32bit）的情况
	              end   
	            2'b10: //Wrapping burst 限度指定长度的突发（一般是这个吧）
	            // The write address wraps when the address reaches wrap boundary 写入地址会在写入边界的时发生循环变换
	              if (aw_wrap_en)
	                begin
	                  axi_awaddr <= (axi_awaddr - aw_wrap_size); 
	                end
	              else 
	                begin
	                  axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                  axi_awaddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}}; 
	                end                      
	            default: //reserved (incremental burst for example)
	              begin
	                axi_awaddr <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                //for awsize = 4 bytes (010)
	              end
	          endcase              
	        end
	    end 
	end       
	// Implement axi_wready generation

	// axi_wready is asserted for one S_AXI_ACLK clock cycle when both
	// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is 
	// de-asserted when reset is low. 

	always_ff @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_wready <= 1'b0;
	    end 
	  else
	    begin    
	      if ( ~axi_wready && S_AXI_WVALID && axi_awv_awr_flag)
	        begin
	          // slave can accept the write data
	          axi_wready <= 1'b1;
	        end
	      //else if (~axi_awv_awr_flag)
	      else if (S_AXI_WLAST && axi_wready)
	        begin
	          axi_wready <= 1'b0;
	        end
	    end 
	end       
	// Implement write response logic generation

	// The write response and response valid signals are asserted(置位) by the slave 
	// when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.  
	// This marks the acceptance of address and indicates(标志) the status of 
	// write transaction.

	always_ff @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_bvalid <= 0;
	      axi_bresp <= 2'b0;
	      axi_buser <= 0;
	    end 
	  else
	    begin    
	      if (axi_awv_awr_flag && axi_wready && S_AXI_WVALID && ~axi_bvalid && S_AXI_WLAST )
					//写通道握手、最后一个数据
	        begin
	          axi_bvalid <= 1'b1;
	          axi_bresp  <= 2'b0; 
	          // 'OKAY' response 
	        end                   
	      else
	        begin
	          if (S_AXI_BREADY && axi_bvalid) 
	          //check if bready is asserted while bvalid is high) 
	          //(there is a possibility that bready is always asserted high)   
	            begin
	              axi_bvalid <= 1'b0; 
	            end  
	        end
	    end
	 end   
	 //********************************************************************Read*********************************
	// Implement axi_arready generation


	// axi_arready is asserted for one S_AXI_ACLK clock cycle when
	// S_AXI_ARVALID is asserted. axi_awready is 
	// de-asserted when reset (active low) is asserted. 
	// The read address is also latched when S_AXI_ARVALID is 
	// asserted. axi_araddr is reset to zero on reset assertion.

	always_ff @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_arready <= 1'b0;
	      axi_arv_arr_flag <= 1'b0;
	    end 
	  else
	    begin    
	      if (~axi_arready && S_AXI_ARVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)
					//读地址通道准备 怎么感觉axi_arv_arr_flag这个有点难绷？
	        begin
	          axi_arready <= 1'b1;
	          axi_arv_arr_flag <= 1'b1;
	        end
	      else if (axi_rvalid && S_AXI_RREADY && axi_arlen_cntr == axi_arlen)
	      // preparing to accept next address after current read completion
	        begin
	          axi_arv_arr_flag  <= 1'b0;
	        end
	      else        
	        begin
	          axi_arready <= 1'b0;
	        end
	    end 
	end       
	// Implement axi_araddr latching

	//This process is used to latch the address when both 
	//S_AXI_ARVALID and S_AXI_RVALID are valid. 
	always_ff @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_araddr <= 0;
	      axi_arlen_cntr <= 0;
	      axi_arburst <= 0;
	      axi_arlen <= 0;
	      axi_rlast <= 1'b0;
	      axi_ruser <= 0;
	    end 
	  else
	    begin    
	      if (~axi_arready && S_AXI_ARVALID && ~axi_arv_arr_flag)
	        begin
	          // address latching 
	          axi_araddr <= S_AXI_ARADDR[C_S_AXI_ADDR_WIDTH - 1:0]; 
	          axi_arburst <= S_AXI_ARBURST; 
	          axi_arlen <= S_AXI_ARLEN;     
	          // start address of transfer
	          axi_arlen_cntr <= 0;
	          axi_rlast <= 1'b0;
	        end   
	       else if((axi_arlen_cntr <= axi_arlen) && axi_rvalid && S_AXI_RREADY)         
	        begin
	         
	          axi_arlen_cntr <= axi_arlen_cntr + 1;
	          axi_rlast <= 1'b0;
	        
	          case (axi_arburst)
	            2'b00: // fixed burst(固定突发传输)
	             // The read address for all the beats in the transaction are fixed
	              begin
	                axi_araddr       <= axi_araddr;        
	                //for arsize = 4 bytes (010)
	              end   
	            2'b01: //incremental burst（增量突发）
	            // The read address for all the beats in the transaction are increments by awsize
	              begin
	                axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1; 
	                //araddr aligned to 4 byte boundary
	                axi_araddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
	                //for awsize = 4 bytes (010)
	              end   
	            2'b10: //Wrapping burst（循环突发）
	            // The read address wraps when the address reaches wrap boundary 
	              if (ar_wrap_en) 
	                begin
	                  axi_araddr <= (axi_araddr - ar_wrap_size); 
	                end
	              else 
	                begin
	                axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1; 
	                //araddr aligned to 4 byte boundary
	                axi_araddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
	                end                      
	            default: //reserved (incremental burst for example)
	              begin
	                axi_araddr <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB]+1;
	                //for arsize = 4 bytes (010)
	              end
	          endcase              
	        end
	      else if((axi_arlen_cntr == axi_arlen) && ~axi_rlast && axi_arv_arr_flag )   
	        begin
	          axi_rlast <= 1'b1;//最后一个读数据
	        end          
	      else if (S_AXI_RREADY)   
	        begin
	          axi_rlast <= 1'b0;
	        end          
	    end 
	end       
	// Implement axi_arvalid generation

	// axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both 
	// S_AXI_ARVALID and axi_arready are asserted. The slave registers 
	// data are available on the axi_rdata bus at this instance. The 
	// assertion of axi_rvalid marks the validity of read data on the 
	// bus and axi_rresp indicates the status of read transaction.axi_rvalid 
	// is deasserted on reset (active low). axi_rresp and axi_rdata are 
	// cleared to zero on reset (active low).  

	always_ff @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_rvalid <= 0;
	      axi_rresp  <= 0;
	    end 
	  else
	    begin    
	      if (axi_arv_arr_flag && ~axi_rvalid)
	        begin
	          axi_rvalid <= 1'b1;
	          axi_rresp  <= 2'b0; 
	          // 'OKAY' response
	        end   
	      else if (axi_rvalid && S_AXI_RREADY)
	        begin
	          axi_rvalid <= 1'b0;
	        end            
	    end
	end    

	// Add user logic here
	//*********************************************BRAM*********************
	//RAM地址更新（Ram 也是一样的32bit）
	assign bram_clk = S_AXI_ACLK;
	assign bram_rstn = !S_AXI_ARESETN;
	assign bram_wrdata = S_AXI_WDATA;
	//通过AXI_slave向RAM写数据，寄存器更新
	assign bram_addr = (axi_arv_arr_flag? axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:(axi_awv_awr_flag? axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:0));
	//RAM读写信号控制
	assign bram_we = (axi_awv_awr_flag)? 4'b1111: 4'b0000;
	assign bram_en = (((axi_awlen_cntr <= axi_awlen) && w_w_active) || (axi_arv_arr_flag));
	// User logic ends
endmodule
